﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Logic.Units;

namespace Logic.Locations
{
    /// <summary>
    ///     Сектор
    /// </summary>
    public class Sector : IEnumerable<IUnit>
    {
        /// <summary>
        ///     Перечень соседних секторов
        /// </summary>
        public List<int> Adjacent = new List<int>();

        /// <summary>
        ///     Защитники
        /// </summary>
        public List<IUnit> Defenders = new List<IUnit>();

        /// <summary>
        ///     К какой локации принадлежит сектор
        /// </summary>
        private Location _parent;

        /// <summary>
        ///     Сотояние сектора
        /// </summary>
        public SectorState State
        {
            get
            {
                if (Defenders.Count > 0)
                {
                    return Defenders[0].State == UserState.Player ? SectorState.Player : SectorState.Enemy;
                }
                return SectorState.Free;
            }
        }

        /// <summary>
        ///     Общее количество войск
        /// </summary>
        public int Count
        {
            get { return Defenders.Sum(x => x.Count); }
        }

        /// <summary>
        ///     ID Сектора на локации
        /// </summary>
        public int ID { get; private set; }

        public Sector(int id)
        {
            ID = id;
        }

        /// <summary>
        ///     Очистка сектора
        /// </summary>
        public void Clear()
        {
            Defenders.Clear();
        }

        /// <summary>
        ///     Установление локации к которой принадлежит сектор
        /// </summary>
        /// <param name="parent">Локация</param>
        public void SetParent(Location parent)
        {
            _parent = parent;
        }

        /// <summary>
        ///     Добавление войск
        /// </summary>
        /// <param name="list">Отряды</param>
        public void AddReinforcement(IEnumerable<IUnit> list)
        {
            foreach (IUnit item in list)
            {
                AddReinforcement(item);
            }
        }

        /// <summary>
        ///     Добавление войск
        /// </summary>
        /// <param name="item">Отряд</param>
        public void AddReinforcement(IUnit item)
        {
            if (Defenders.Any(y => y.State != item.State))
            {
                throw new Exception("Попытка соединить войска противостоящих сторон");
            }

            IUnit unit = Defenders.FirstOrDefault(x => x.GetType() == item.GetType());

            if (unit == null)
            {
                Defenders.Add((IUnit) item.Clone());
            }
            else
            {
                unit.Add(item);
            }
        }

        /// <summary>
        ///     Задать войск
        /// </summary>
        /// <param name="item">Отряд</param>
        public void SetReinforcement(IUnit item)
        {
            if (Defenders.Any(y => y.State != item.State))
            {
                throw new Exception("Попытка соединить войска противостоящих сторон");
            }
            IUnit unit = Defenders.FirstOrDefault(x => x.GetType() == item.GetType());

            if (unit != null)
            {
                Defenders.Remove(unit);
            }
            Defenders.Add((IUnit) item.Clone());
        }

        /// <summary>
        ///     Удаление войск
        /// </summary>
        /// <param name="unitToMove">Отряды</param>
        public void RemoveReinforcement(IEnumerable<IUnit> unitToMove)
        {
            foreach (IUnit item in unitToMove)
            {
                RemoveReinforcement(item);
            }
        }

        /// <summary>
        ///     Удаление отряда
        /// </summary>
        /// <param name="item">Отряд</param>
        public void RemoveReinforcement(IUnit item)
        {
            IUnit unit = Defenders.FirstOrDefault(x => x.GetType() == item.GetType()
                                                       && x.State == item.State);
            if (unit != null && item.Count <= unit.Count)
            {
                unit.Count -= item.Count;
                foreach (IUnit defender in Defenders.ToList()
                    .Where(defender => defender.Count <= 0))
                {
                    Defenders.Remove(defender);
                }
            }
            else
            {
                throw new Exception("Попытка списать несуществующие войска");
            }
        }

        /// <summary>
        ///     Возможен ли ход
        /// </summary>
        /// <param name="inSector">Из какого секора</param>
        /// <param name="sector">В какой сектор</param>
        /// <returns>Сектора находятся рядом</returns>
        public bool Possibly(Sector sector)
        {
            return Adjacent.Contains(sector.ID) && sector.Adjacent.Contains(ID);
        }

        #region IEnumerator<IUnit>

        public IEnumerator<IUnit> GetEnumerator()
        {
            return Defenders.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        #endregion
    }
}